if ('function' !== typeof RegExp.escape) {
	RegExp.escape = function(s) {
		if ('string' !== typeof s) {
			return s;
		}
		// Note: if pasting from forum, precede ]/\ with backslash manually
		return s.replace(/([.*+?^=!:${}()|[\]\/\\])/g, '\\$1');
	}; // eo function escape
}
Ext.ns('Ext.ux.form');
Ext.ux.form.LovCombo = Ext.extend(Ext.form.ComboBox, {
	emptyText : "---请选择---",
	checkField : 'checked',
	valueField : "id",
	separator : ',',
	user1Blank : false,
	checkModel : 'multiple',// single:单选,multiple:多选

	constructor : function(config) {
		config = config || {};
		config.listeners = config.listeners || {};
		Ext.applyIf(config.listeners, {
			scope : this,
			beforequery : this.onBeforeQuery,
			blur : this.onRealBlur
		});
		Ext.ux.form.LovCombo.superclass.constructor.call(this, config);
	},
	initComponent : function() {
		// template with checkbox
		if (!this.tpl) {
			this.tpl = '<tpl for=".">' + '<div class="x-combo-list-item">' + '<img src="' + Ext.BLANK_IMAGE_URL + '" '
					+ 'class="ux-lovcombo-icon ux-lovcombo-icon-' + '{[values.' + this.checkField + '?"checked":"unchecked"' + ']}">'
					+ '<div class="ux-lovcombo-item-text">{' + (this.displayField || 'text') + '}</div>' + '</div>' + '</tpl>';
		}
		// call parent
		Ext.ux.form.LovCombo.superclass.initComponent.apply(this, arguments);
		// remove selection from input field
		this.onLoad = this.onLoad.createSequence(function() {
			if (this.el) {
				var v = this.el.dom.value;
				this.el.dom.value = '';
				this.el.dom.value = v;
			}
		});
	}

	,
	initEvents : function() {
		Ext.ux.form.LovCombo.superclass.initEvents.apply(this, arguments);
		this.keyNav.tab = false;
	}

	,
	clearValue : function() {
		this.value = '';
		this.setRawValue(this.value);
		this.store.clearFilter();
		this.store.each(function(r) {
			r.set(this.checkField, false);
		}, this);
		if (this.hiddenField) {
			this.hiddenField.value = '';
		}
		this.applyEmptyText();
	}

	,
	getCheckedDisplay : function() {
		var re = new RegExp(this.separator, "g");
		return this.getCheckedValue(this.displayField).replace(re, this.separator);
	}

	,
	getCheckedValue : function(field) {
		field = field || this.valueField;
		var c = [];
		// store may be filtered so get all records
		var snapshot = this.store.snapshot || this.store.data;
		snapshot.each(function(r) {
			if (r.get(this.checkField)) {
				c.push(r.get(field));
			}
		}, this);
		return c.join(this.separator);
	}

	,
	onBeforeQuery : function(qe) {
		qe.query = qe.query.replace(new RegExp(RegExp.escape(this.getCheckedDisplay()) + '[ ' + this.separator + ']*'), '');
	}

	,
	onRealBlur : function() {
		this.list.hide();
		var rv = this.getRawValue();
		var rva = rv.split(new RegExp(RegExp.escape(this.separator) + ' *'));
		var va = [];
		var snapshot = this.store.snapshot || this.store.data;

		// iterate through raw values and records and check/uncheck items
		Ext.each(rva, function(v) {
			snapshot.each(function(r) {
				if(v === r.get(this.displayField)) {
					va.push(r.get(this.valueField));
				}
			}, this);
		}, this);
		this.setValue(va.join(this.separator));
		this.store.clearFilter()
	}

	,
	onSelect : function(record, index) {
		if (this.checkModel === 'single') {
			this.clearValue();
		}
		if (this.fireEvent('beforeselect', this, record, index) !== false) {
			record.set(this.checkField, !record.get(this.checkField));
			if (this.store.isFiltered()) {
				this.doQuery(this.allQuery);
			}
			// set (update) value and fire event
			this.setValue(this.getCheckedValue());
			this.fireEvent('select', this, record, index);
		}
	}

	,
	setValue : function(v) {
		if (v) {
			v = '' + v;
			if (this.valueField) {
				this.store.clearFilter();
				this.store.each(function(r) {
					var checked = !(!v.match('(^|' + this.separator + ')' + RegExp.escape(r.get(this.valueField)) + '(' + this.separator + '|$)'));
					r.set(this.checkField, checked);
				}, this);
				this.value = this.getCheckedValue();
				this.setRawValue(this.getCheckedDisplay());
				if (this.hiddenField) {
					this.hiddenField.value = this.value;
				}
			} else {
				this.value = v;
				this.setRawValue(v);
				if (this.hiddenField) {
					this.hiddenField.value = v;
				}
			}
			if (this.el) {
				this.el.removeClass(this.emptyClass);
			}
		} else {
			this.clearValue();
		}
	},
	beforeBlur : function() {
		var val = this.getRawValue();
		if (this.forceSelection) {
			if (val.length > 0 && val != this.emptyText) {
				this.el.dom.value = Ext.isDefined(this.lastSelectionText) ? this.lastSelectionText : '';
				this.applyEmptyText();
			} else {
				this.clearValue();
			}
		} else {
			if (this.firstLoaded) {
				var texts = val.split(',');
				var values = '';
				for ( var i = 0; i < texts.length; i++) {
					var rec = this.findRecord(this.displayField, texts[i].trim());
					if (rec) {
						values += (values.length > 0 ? ',' : '') + rec.data[this.valueField];
					}
				}
				this.setValue(values);
			}
		}
	},
	selectAll : function() {
		this.store.each(function(record) {
			// toggle checked field
			record.set(this.checkField, true);
		}, this);
		// display full list
		this.doQuery(this.allQuery);
		this.setValue(this.getCheckedValue());
	}

	,
	initValue : function() {
		if (!Ext.isDefined(this.value)) {
			this.value = this.el.dom.value;
		}
		if (this.hiddenField) {
			if (Ext.isDefined(this.hiddenValue)) {
				this.hiddenField.value = this.hiddenValue;
			}
		}
	}

	,
	bindStore : function(store, initial) {
		Ext.ux.form.LovCombo.superclass.bindStore.call(this, store, initial);
		if (this.view && !this.bindViewEvented) {
			this.bindViewEvented = true;
			if (this.view.rendered) {
				this.view.getStore().on("load", function(store, records) {
					this.firstLoaded = true;
					this.echoChecked(store, records);
				}, this);
			}
		}
	}

	,
	echoChecked : function(store, records) {
		if (this.hiddenField) {
			var value = this.hiddenField.value;
			if (!K.isBlank(value)) {
				var me = this;
				if (this.checkModel == 'multiple') {
					var valueMap = K.arrayToMap(value.split(this.separator));
					$.each(records, function(i, record) {
						if (valueMap[record.get(me.valueField)] != undefined) {
							record.set(me.checkField, true)
						}
					});
				} else {
					$.each(records, function(i, record) {
						if (record.get(me.valueField) == value) {
							record.set(me.checkField, true)
						}
					});
				}
			}
		}
	}

	,
	deselectAll : function() {
		this.clearValue();
	}
});
Ext.reg('lovcombo', Ext.ux.form.LovCombo);